﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Microsoft.WindowsServerSolutions.AddinInfrastructure;
using Microsoft.WindowsServerSolutions.Common;
using Microsoft.WindowsServerSolutions.Properties;

namespace TV4Home.Server.Vail.AddIn
{
    public partial class CheckForUpdatesForm : PropertyForm
    {
        public CheckForUpdatesForm()
        {
            InitializeComponent();

            this.lblCurrentVersion.Text = Utils.Misc.AddInVersion;
            this.SetButtonVisiblity(true, false, false);

            SearchForUpdates();
        }

        protected override void OnOKButtonClicked(EventArgs e)
        {
            this.Close();
        }

        private void wbReleaseNotes_Navigating(object sender, WebBrowserNavigatingEventArgs e)
        {
            if (e.Url.AbsoluteUri == "about:blank")
                return;

            // launch external urls on the Client
            e.Cancel = true;

            VirtualChannelActions.OpenURLOnClientAndFallbackToServer(e.Url);
        }

        private void SearchForUpdates()
        {
            bgwCheckForUpdates.RunWorkerAsync();
        }

        private void bgwCheckForUpdates_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                if (CheckForUpdates())
                {
                    this.Invoke(new Action(() => this.lblStatus.Text = "A new version is available!"));
                    this.Invoke(new Action(() => pnNewVersionAvailable.Visible = true));
                }
                else
                {
                    this.Invoke(new Action(() => this.lblStatus.Text = "Your version is up to date!"));
                }
            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() => this.lblStatus.Text = "Error while checking for updates: " + ex.Message));
            }
        }

        /// <summary>
        /// Checks for updates.
        /// </summary>
        /// <returns>True if there is a newer version on the Internet, otherwise false.</returns>
        private bool CheckForUpdates()
        {
            Regex versionNumberRegex = new Regex(@"(?<Major>\d*)\.(?<Minor>\d*)(\.(?<Build>\d*)(\.(?<Revision>\d*))?)?");

            // load the Codeplex Releases RSS feed
            SyndicationFeed projectRssFeed = SyndicationFeed.Load(System.Xml.XmlReader.Create("http://tv4home.codeplex.com/Project/ProjectRss.aspx?ProjectRSSFeed=codeplex%3a%2f%2frelease%2fTV4Home"));

            if (projectRssFeed == null)
                throw new InvalidOperationException("The update RSS feed couldn't be retrieved.");

            if (projectRssFeed.Items.Count() == 0)
                throw new InvalidOperationException("The update RSS feed is empty.");

            // get the latest item in the feed
            SyndicationItem latestItem = projectRssFeed.Items.First();

            // retrieve version number from feed item title
            Match regExMatch = versionNumberRegex.Match(latestItem.Title.Text);
            Version versionOnInternet = regExMatch.Success ? new Version(regExMatch.Value) : new Version("0.0.0.0");

            // if the version on the Internet is newer than the local version -> show notification
            if (new Version(Utils.Misc.AddInVersion) < versionOnInternet)
            {
                this.Invoke(new Action(() => this.lblNewVersion.Text = versionOnInternet.ToString()));
                this.Invoke(new Action(() => this.wbReleaseNotes.DocumentText = latestItem.Summary.Text));

                new AddInManager().NewAddInVersionAvailable(Guid.NewGuid(), versionOnInternet, latestItem.Links.First().Uri, UpdateClassification.Update);

                return true;
            }

            // version is up to date
            return false;
        }
    }
}

